#include "SpyKit.h"

#include <stdio.h>

void SpyKit::clean()
{
	SpyCallNumber = 0;
	phandle = 0;
	mapHandle = 0;
	mapMemory = 0;
	isHook = false;
}

SpyKit::SpyKit()
{
	clean();
}

SpyKit::~SpyKit()
{
	if(isHook)
		stopHook();

	if(phandle)
		CloseHandle(phandle);

	if(mapMemory)
		UnmapViewOfFile(mapMemory);

	if(mapHandle)
		CloseHandle(mapHandle);
	
	clean();
}

void* SpyKit::openMap(LPCSTR memory_id)
{
	if(mapMemory != 0)
	{
		SpyError("allready open map!");
		return mapMemory;
	}
	
	HANDLE map_h = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,(LPCSTR)memory_id);
	if( NULL == map_h )
	{
		SpyError("OpenFileMapping Failed!");
		return 0;
	}

	void* data = MapViewOfFile(map_h,FILE_MAP_ALL_ACCESS,0,0,0);
	if( NULL == data)
	{
		SpyError("MapViewOfFile Failed!");
		return 0;
	}

	mapHandle = map_h;
	mapMemory = data;

	return mapMemory;
}

int SpyKit::initHandleByPID(DWORD processID)
{
	phandle = OpenProcess(PROCESS_ALL_ACCESS,NULL,processID);

	if(phandle == NULL)
		return SpyError("getHandle error!");

	return 0;
}

int	SpyKit::setCall(DWORD ORI_call_address,DWORD SPY_call_address)
{
	if(phandle == 0)
		return SpyError("phandle is null!");

	if(SpyCallNumber == SPY_MAX)
		return SpyError("hookcalls number allready max!");

	DWORD instructionAddress = ORI_call_address;
	DWORD offset_original = 0;

	BOOL result =ReadProcessMemory(phandle,(LPVOID)(instructionAddress + 1),&offset_original,sizeof(DWORD),NULL);
	if(result == FALSE)
		return SpyError("SetCall ReadProcessMemory failed!");

	DWORD NewCallAddress = (DWORD)SPY_call_address;
	DWORD offset_new = NewCallAddress - instructionAddress - sizeof(DWORD) - 1;

	hookCalls[SpyCallNumber].origianl_call_address = instructionAddress;
	hookCalls[SpyCallNumber].original_call_offset  = offset_original;
	hookCalls[SpyCallNumber].spy_call_offset	   = offset_new;

	return SpyCallNumber++;
}

int SpyKit::beginHook()
{
	for(int i = 0 ; i < SpyCallNumber ; i ++)
	{
		DWORD instructionAddress = hookCalls[i].origianl_call_address;
		DWORD offset			 = hookCalls[i].spy_call_offset;

		if(FALSE == WriteProcessMemory(phandle,(LPVOID)(instructionAddress + 1),&offset,sizeof(DWORD),NULL))
		{
			return SpyError("beginHook WriteProcessMemory failed!");
		}
	}

	isHook = true;
	return 0;
}

int	SpyKit::stopHook()
{

	for(int i = 0 ; i < SpyCallNumber ; i ++)
	{
		DWORD instructionAddress = hookCalls[i].origianl_call_address;
		DWORD offset			 = hookCalls[i].original_call_offset;

		if(FALSE == WriteProcessMemory(phandle,(LPVOID)(instructionAddress + 1),&offset,sizeof(DWORD),NULL))
		{
			return SpyError("stopHook WriteProcessMemory failed!");
		}
	}

	isHook = false;
	return 0;
}

DWORD SpyKit::getOriginalCallAddress(int index)
{
	if(index >= SpyCallNumber || index < 0)
		return SpyError("Out of index");

	DWORD Call_Address = 
		hookCalls[index].origianl_call_address + 1 + hookCalls[index].original_call_offset + sizeof(DWORD);	

	return Call_Address;
}


int SpyKit::SpyError(char* message)
{
	int code = ::GetLastError();
	char error_tips[1024] = {0};
	sprintf(error_tips,"%s Error:%d",message,code);
	MessageBoxA(NULL,message,"ERROR",MB_OK);
	return code;
}